Meteo.f90 Source File

Manage meteorological forcings



Source Code

!! Manage meteorological forcings
!|author:  <a href="mailto:giovanni.ravazzani@polimi.it">Giovanni Ravazzani</a>
! license: <a href="http://www.gnu.org/licenses/">GPL</a>
!    
!### History
!
! current version  1.1 - 2nd February 2023  
!
! | version  |  date       |  comment |
! |----------|-------------|----------|
! | 1.0      | 17/Oct/2017 | Original code |
! | 1.1      | 02/Feb/2023 | added subroutine to export point data |
!
!### License  
! license: GNU GPL <http://www.gnu.org/licenses/>
!
!### Module Description 
! Module to manage meteorological forcings
!
MODULE Meteo      


! Modules used: 

USE DataTypeSizes, ONLY : &  
  ! Imported Parameters:
  float, short


USE Loglib, ONLY : &
  !Imported routines:
  Catch

USE IniLib, ONLY : &
  !Imported types:
  IniList, &
  !Imported routines:
  IniOpen, SectionIsPresent, &
  IniClose

USE GridLib, ONLY : &
  !Imported types:
  grid_real, grid_integer

USE Precipitation, ONLY : &
  !Imported routines:
  PrecipitationInit, PrecipitationRead, &
  !Imported variables:
  dtPrecipitation, precipitationRate

USE PrecipitationDaily, ONLY : &
  !Imported routines:
  PrecipitationDailyInit, PrecipitationDailyRead, &
  !Imported variables:
  dtPrecipitationDaily

USE AirTemperature, ONLY : &
  !Imported routines:
  AirTemperatureInit, AirTemperatureRead, &
  !Imported variables:
  dtTemperature, temperatureAir

USE AirTemperatureDailyMean, ONLY : &
  !Imported routines:
  AirTemperatureDailyMeanInit, AirTemperatureDailyMeanRead, &    
  !Imported variables:
  dtTemperatureDailyMean

USE AirTemperatureDailyMax, ONLY : &
  !Imported routines:
  AirTemperatureDailyMaxInit, AirTemperatureDailyMaxRead, &    
  !Imported variables:
  dtTemperatureDailyMax

USE AirTemperatureDailyMin, ONLY : &
  !Imported routines:
  AirTemperatureDailyMinInit, AirTemperatureDailyMinRead, &    
  !Imported variables:
  dtTemperatureDailyMin

USE SolarRadiation, ONLY : &
  !Imported routines:
  SolarRadiationInit, SolarRadiationRead, &    
  !Imported variables:
  dtRadiation, radiation

USE AirRelativeHumidity, ONLY : &
  !Imported routines:
  AirRelativeHumidityInit, AirRelativeHumidityRead, &    
  !Imported variables:
  dtRelHumidity, relHumidityAir

USE WindFlux, ONLY : &
  !Imported routines:
  WindFluxInit, WindFluxRead, &
  !Imported variables:
  dtWindSpeed, windSpeed

USE Chronos, ONLY : &
  !Imported types:
  DateTime, &
  !Imported operators:
  OPERATOR (==), & 
  OPERATOR (+)

USE ObservationalNetworks, ONLY : &
  !Imported routines:
  ReadMetadata, CopyNetwork, &
  WriteMetadata, DestroyNetwork, &
  AssignDataFromGrid, WriteData, &
  !Imported defined variable:
  ObservationalNetwork

USE Utilities, ONLY : &
  !Imported routines:
  GetUnit

IMPLICIT NONE 

! Global (i.e. public) Declarations: 

INTEGER (KIND = short) :: dtMeteo
LOGICAL :: demHiResRequired = .FALSE.

!Public routines
PUBLIC :: MeteoInit
PUBLIC :: MeteoRead
PUBLIC :: MeteoPointInit


!Local (i.e. private) declarations 
TYPE (IniList), PRIVATE :: meteoini
TYPE (ObservationalNetwork), PRIVATE :: sites
TYPE (ObservationalNetwork), PRIVATE :: sitesPrecipitation 
TYPE (ObservationalNetwork), PRIVATE :: sitesTemperature
TYPE (ObservationalNetwork), PRIVATE :: sitesRadiation
TYPE (ObservationalNetwork), PRIVATE :: sitesRH
TYPE (ObservationalNetwork), PRIVATE :: sitesWS
INTEGER (KIND = short), PRIVATE :: fileUnitPointPrecipitation
INTEGER (KIND = short), PRIVATE :: fileUnitPointTemperature
INTEGER (KIND = short), PRIVATE :: fileUnitPointRadiation
INTEGER (KIND = short), PRIVATE :: fileUnitPointRH
INTEGER (KIND = short), PRIVATE :: fileUnitPointWS
INTEGER (KIND = short), PRIVATE :: timeIncrementSites
TYPE (DateTime), PRIVATE :: timePointExport



!Private routines

PRIVATE :: MeteoPointExport


!Local routines

!=======
CONTAINS
!=======
! Define procedures contained in this module.


!==============================================================================
!| Description:
!   Initialize meteorological forcings
SUBROUTINE MeteoInit &
!
( inifile, tstart, mask, dem, dem_loaded, albedo_loaded )

IMPLICIT NONE


CHARACTER (LEN = *), INTENT(IN) :: inifile  !!name of configuration file
TYPE (DateTime),     INTENT(IN) :: tstart !!initial time
TYPE (grid_integer), INTENT(IN) :: mask  !!defines interpolation extent
!INTEGER (KIND = short), INTENT(IN) :: dtMeteo !! deltat of meteo data reading
TYPE(grid_real), INTENT(in) :: dem !!digital elevation model to be used to modify interpolated data
LOGICAL , INTENT (in) :: dem_loaded !! true if dem has been loaded
LOGICAL , INTENT (in) :: albedo_loaded !! true if dem has been loaded

!-------------------------end of declarations----------------------------------

!open and load configuration file
CALL IniOpen (inifile, meteoini)

!configure precipitation
IF (SectionIsPresent (section = "precipitation", iniDB = meteoini))  THEN
   CALL Catch ('info', 'Meteo', 'initialize precipitation ')
   CALL PrecipitationInit (meteoini, mask, dtMeteo, tstart, dem_loaded)
ELSE 
    CALL Catch ('warning', 'Meteo', 'precipitation is turned off')
END IF

!configure daily precipitation
IF (SectionIsPresent (section = "precipitation-daily", iniDB = meteoini))  THEN
   CALL Catch ('info', 'Meteo', 'initialize daily precipitation ')
   CALL PrecipitationDailyInit (meteoini, mask, dtMeteo, tstart, dem_loaded)
ELSE 
    CALL Catch ('warning', 'Meteo', 'daily precipitation is turned off')
END IF

!configure air temperature
IF (SectionIsPresent (section = "temperature", iniDB = meteoini))  THEN
   CALL Catch ('info', 'Meteo', 'initialize air temperature ')
   CALL AirTemperatureInit (meteoini, mask, dtMeteo, tstart, dem_loaded)
ELSE 
    CALL Catch ('warning', 'Meteo', 'air temperature is turned off')
END IF

!configure mean daily air temperature
IF (SectionIsPresent (section = "temperature-daily-mean", iniDB = meteoini))  THEN
   CALL Catch ('info', 'Meteo', 'initialize daily mean air temperature ')
   CALL AirTemperatureDailyMeanInit (meteoini, mask, dtMeteo, tstart, dem_loaded)
ELSE 
    CALL Catch ('warning', 'Meteo', 'daily mean air temperature is turned off')
END IF

!configure maximum daily air temperature
IF (SectionIsPresent (section = "temperature-daily-max", iniDB = meteoini))  THEN
   CALL Catch ('info', 'Meteo', 'initialize daily max air temperature ')
   CALL AirTemperatureDailyMaxInit (meteoini, mask, dtMeteo, tstart, dem_loaded)
ELSE 
    CALL Catch ('warning', 'Meteo', 'daily max air temperature is turned off')
END IF

!configure minimum daily air temperature
IF (SectionIsPresent (section = "temperature-daily-min", iniDB = meteoini))  THEN
   CALL Catch ('info', 'Meteo', 'initialize daily min air temperature ')
   CALL AirTemperatureDailyMinInit (meteoini, mask, dtMeteo, tstart, dem_loaded)
ELSE 
    CALL Catch ('warning', 'Meteo', 'daily min air temperature is turned off')
END IF

!configure relative humidity
IF (SectionIsPresent (section = "relative-humidity", iniDB = meteoini))  THEN
   CALL Catch ('info', 'Meteo', 'initialize relative humidity ')
   CALL AirRelativeHumidityInit (meteoini, mask, dtMeteo, tstart)
ELSE 
    CALL Catch ('warning', 'Meteo', 'relative humidity is turned off')
END IF

!configure solar radiation
IF (SectionIsPresent (section = "solar-radiation", iniDB = meteoini))  THEN
   CALL Catch ('info', 'Meteo', 'initialize solar radiation ')
   CALL SolarRadiationInit (meteoini, mask, dtMeteo, tstart, dem, dem_loaded, &
                            albedo_loaded, dtTemperature, dtRelHumidity )
ELSE 
    CALL Catch ('warning', 'Meteo', 'solar radiation is turned off')
END IF

!configure wind speed
IF (SectionIsPresent (section = "wind-speed", iniDB = meteoini))  THEN
   CALL Catch ('info', 'Meteo', 'initialize wind flux ')
   CALL WindFluxInit (meteoini, mask, dtMeteo, tstart, dem, dem_loaded)
ELSE 
    CALL Catch ('warning', 'Meteo', 'wind speed is turned off')
END IF

!close ini
CALL IniClose (meteoini)

RETURN
END SUBROUTINE MeteoInit


!==============================================================================
!| Description:
!   Initialize export of point site data
SUBROUTINE MeteoPointInit &
!
( pointfile, path_out, time )

IMPLICIT NONE

!Arguments with intent (in):
CHARACTER (LEN = *), INTENT(IN) :: pointfile  !!file containing coordinate of points
CHARACTER (LEN = *), INTENT(IN) :: path_out  !!path of output folder
TYPE (DateTime),     INTENT(IN) :: time  !!start time

!local declarations
INTEGER (KIND = short) :: err_io
INTEGER (KIND = short) :: fileunit

!-------------------------end of declarations----------------------------------

timePointExport = time

!open point file

fileunit = GetUnit ()
OPEN ( unit = fileunit, file = pointfile(1:LEN_TRIM(pointfile)), &
      status='OLD', iostat = err_io )

IF ( err_io /= 0 ) THEN
	!file does not exist
    CALL Catch ('error', 'Meteo', 'out point file does not exist')
END IF 

!Read metadata
CALL ReadMetadata (fileunit, sites)

!set time increment
timeIncrementSites = sites % timeIncrement

!check dt
IF (.NOT. ( MOD ( sites % timeIncrement, dtMeteo ) == 0 ) ) THEN
  CALL Catch ('error', 'Meteo', 'dt out sites must be multiple of dtMeteo ')
END IF

CLOSE ( fileunit )

!create virtual network and initialize file for output

!precipitation
IF ( dtPrecipitation > 0 ) THEN
    fileUnitPointPrecipitation = GetUnit ()
    OPEN ( unit = fileUnitPointPrecipitation, &
           file = TRIM(path_out) // 'point_precipitation.fts' )
    
    CALL CopyNetwork ( sites, sitesPrecipitation )

    sitesPrecipitation % description = 'precipitation data exported from FEST'

    sitesPrecipitation % unit = 'mm'

    sitesPrecipitation % offsetZ = 2.

    CALL WriteMetadata ( network = sitesPrecipitation, &
                        fileunit = fileUnitPointPrecipitation )

    CALL WriteData (sitesPrecipitation, fileUnitPointPrecipitation, .TRUE.)
    
END IF

!air temperature
IF ( dtTemperature > 0 ) THEN
    fileUnitPointTemperature = GetUnit ()
    OPEN ( unit = fileUnitPointTemperature, &
           file = TRIM(path_out) // 'point_temperature.fts' )
    
    CALL CopyNetwork ( sites, sitesTemperature )

    sitesTemperature % description = 'air temperature data exported from FEST'

    sitesTemperature % unit = 'degree Celsius'

    sitesTemperature % offsetZ = 2.

    CALL WriteMetadata ( network = sitesTemperature, &
                        fileunit = fileUnitPointTemperature )
    
    CALL WriteData (sitesTemperature, fileUnitPointTemperature, .TRUE.)
    
END IF

!solar radiation
IF ( dtRadiation > 0 ) THEN
    fileUnitPointRadiation = GetUnit ()
    OPEN ( unit = fileUnitPointRadiation, &
           file = TRIM(path_out) // 'point_radiation.fts' )
    
    CALL CopyNetwork ( sites, sitesRadiation )

    sitesRadiation % description = 'solar radiation data exported from FEST'

    sitesRadiation % unit = 'w/m2'

    sitesRadiation % offsetZ = 2.

    CALL WriteMetadata ( network = sitesRadiation, &
                        fileunit = fileUnitPointRadiation )
    
    CALL WriteData (sitesRadiation, fileUnitPointRadiation, .TRUE.)
    
END IF

!air relative humidity
IF ( dtRelHumidity > 0 ) THEN
    fileUnitPointRH = GetUnit ()
    OPEN ( unit = fileUnitPointRH, &
           file = TRIM(path_out) // 'point_RH.fts' )
    
    CALL CopyNetwork ( sites, sitesRH )

    sitesRH % description = 'air relative humidity data exported from FEST'

    sitesRH % unit = '% 0-100'

    sitesRH % offsetZ = 2.

    CALL WriteMetadata ( network = sitesRH, &
                        fileunit = fileUnitPointRH )
    
    CALL WriteData (sitesRH, fileUnitPointRH, .TRUE.)
    
END IF


!wind speed
IF ( dtWindSpeed > 0 ) THEN
    fileUnitPointWS = GetUnit ()
    OPEN ( unit = fileUnitPointWS, &
           file = TRIM(path_out) // 'point_WS.fts' )
    
    CALL CopyNetwork ( sites, sitesWS )

    sitesWS % description = 'wind speed data exported from FEST'

    sitesWS % unit = 'm/s'

    sitesWS % offsetZ = 10.

    CALL WriteMetadata ( network = sitesWS, &
                        fileunit = fileUnitPointWS )
    
    CALL WriteData (sitesWS, fileUnitPointWS, .TRUE.)
    
END IF

! destroy sites
CALL DestroyNetwork ( sites )

RETURN
END SUBROUTINE MeteoPointInit


!==============================================================================
!| Description:
!   Read meteorological forcings
SUBROUTINE MeteoRead &
!
( time, dem, albedo )

IMPLICIT NONE

!Arguments with intent(in):
TYPE (DateTime), INTENT(IN) :: time !!current time
TYPE (grid_real), OPTIONAL, INTENT(IN) :: dem !!used to apply drift of station data
TYPE (grid_real), OPTIONAL, INTENT(IN) :: albedo !!used to apply drift of radiation site data

!-------------------------end of declarations----------------------------------

IF (dtPrecipitation > 0) THEN
   CALL PrecipitationRead (time, dem)
END IF

IF (dtPrecipitationDaily > 0) THEN
   CALL PrecipitationDailyRead (time, dem)
END IF

IF (dtTemperature > 0) THEN
   CALL AirTemperatureRead (time, dem)
END IF

IF (dtTemperatureDailyMean > 0) THEN
   CALL AirTemperatureDailyMeanRead (time, dem)
END IF

IF (dtTemperatureDailyMax > 0) THEN
   CALL AirTemperatureDailyMaxRead (time, dem)
END IF

IF (dtTemperatureDailyMin > 0) THEN
   CALL AirTemperatureDailyMinRead (time, dem)
END IF

IF (dtRelHumidity > 0) THEN
   CALL AirRelativeHumidityRead (time)
END IF

IF (dtRadiation > 0) THEN
   CALL SolarRadiationRead (time, dem, albedo, temperatureAir, relHumidityAir )
END IF

IF (dtWindSpeed > 0) THEN
   CALL WindFluxRead (time, dem)
END IF

IF ( time == timePointExport ) THEN
    CALL MeteoPointExport ( time )
    timePointExport = timePointExport + timeIncrementSites
END IF

RETURN
END SUBROUTINE MeteoRead



!==============================================================================
!| Description:
!   Export of point site data
SUBROUTINE MeteoPointExport &
!
( time )

IMPLICIT NONE

!Arguments with intent(in):
TYPE (DateTime), INTENT (IN) :: time

!local declarations:
INTEGER (KIND = short) :: i


!-------------------------end of declarations----------------------------------


!precipitation
IF ( dtPrecipitation > 0 ) THEN
    !set current time
    sitesPrecipitation % time = time 
    
    !populate data
    CALL AssignDataFromGrid (precipitationRate, sitesPrecipitation )
    
    !unit conversion m/s -> mm
    DO i = 1, sitesPrecipitation % countObs
        IF ( sitesPrecipitation % obs (i) % value /= &
             sitesPrecipitation % nodata ) THEN
            sitesPrecipitation % obs (i) % value = &
            sitesPrecipitation % obs (i) % value * dtPrecipitation * 1000.
        END IF
    END DO
    
    !write data
    CALL WriteData (sitesPrecipitation, fileUnitPointPrecipitation)

END IF

!air temperature
IF ( dtTemperature > 0 ) THEN
    !set current time
    sitesTemperature % time = time 
    
    !populate data
    CALL AssignDataFromGrid (temperatureAir, sitesTemperature )

    !write data
    CALL WriteData (sitesTemperature, fileUnitPointTemperature)

END IF


!solar radiation
IF ( dtRadiation > 0 ) THEN
    !set current time
    sitesRadiation % time = time 
    
    !populate data
    CALL AssignDataFromGrid ( radiation, sitesRadiation )

    !write data
    CALL WriteData ( sitesRadiation, fileUnitPointRadiation )

END IF

!air relative humidity
IF ( dtRelHumidity > 0 ) THEN
    !set current time
    sitesRH % time = time 
    
    !populate data
    CALL AssignDataFromGrid ( relHumidityAir, sitesRH )

    !write data
    CALL WriteData ( sitesRH, fileUnitPointRH )

END IF

!wind speed
IF ( dtWindSpeed > 0 ) THEN
    !set current time
    sitesWS % time = time 
    
    !populate data
    CALL AssignDataFromGrid ( windSpeed, sitesWS )

    !write data
    CALL WriteData ( sitesWS, fileUnitPointWS )

END IF

RETURN
END SUBROUTINE MeteoPointExport


END MODULE Meteo